/*
 *
    RCaller, A solution for calling R from Java
    Copyright (C) 2010  Mehmet Hakan Satman

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Mehmet Hakan Satman - mhsatman@yahoo.com
 * http://www.mhsatman.com

 */


package rcaller;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;



public class RCaller {

    public static String version = "0.5.1";
    public static String author = "Mehmet Hakan Satman - mhsatman@yahoo.com - http://www.mhsatman.com";
    
    bsh.Interpreter Interpreter;
    String libraryCode;
    String Rscript="/usr/bin/Rscript";
    ArrayList<String> fields;

    public RCaller(){
        libraryCode=loadMakeJavaLibrary();
        Interpreter=new bsh.Interpreter();
        fields=new ArrayList<String>();
    }

    public void setRScriptExecutableFile(String location){
        this.Rscript=location;
    }

    public String getRscriptExecutableFile(){
        return(this.Rscript);
    }

    public Object RGet(String s) throws Exception {
        Object o=null;
        o=Interpreter.eval(s);
        if(o==null) throw new Exception("Variable "+s+" could not extracted");
        return(o);
    }

    public double[] RGetAsDoubleArray(String name) throws Exception{
        double[] result=null;
        result=(double[])Interpreter.eval(name);
        if(result==null) throw new Exception("Double array "+name+" could not extracted");
        return(result);
    }

    public String[] RGetAsStringArray(String name) throws Exception{
        String[] result=null;
        result=(String[])Interpreter.eval(name);
        if(result==null) throw new Exception("String array "+name+" could not extracted");
        return(result);
    }

    public void RunRCode(String code) throws Exception{
        StringBuffer buf=new StringBuffer();
        buf.append(this.libraryCode);
        buf.append("\n\n");
        buf.append(code);
        File Rcode;
        Rcode=File.createTempFile("R2J", ".r");
        writeFile(Rcode, buf.toString());
        Runtime r=Runtime.getRuntime();
        Process p=r.exec(new String[]{this.Rscript,Rcode.toString()});
        BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));

        while (true){
            String s=reader.readLine();
            if (s==null) break;
            //System.out.println("Getting "+s);
            registerField(s);
            Interpreter.eval(s);
        }
        
    }

    private void registerField(String entry){
        try{
            String[] buf=entry.split("=");
            this.fields.add(buf[0]);
        }catch(Exception e){
            System.out.println(e);
        }
    }

    public ArrayList<String> getFieldList(){
        return(this.fields);
    }

    final private String loadMakeJavaLibrary(){
        StringBuffer buf=new StringBuffer();
        try{
             BufferedReader reader=new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("makejava.r")));
             char[] c=new char[1];
             int res;
             while(true){
                res=reader.read(c);
                if (res<0) break;
                buf.append(c);
             }
             reader.close();
        }catch (Exception e){
             System.out.println(e.toString());
        }
        return(buf.toString());
    }

    final private void writeFile(File f, String s){
        try{
            BufferedWriter writer=new BufferedWriter(new FileWriter(f));
            writer.write(s);
            writer.flush();
            writer.close();
        }catch (Exception e){
            System.out.println(e.toString());
        }
    }

    final private String readFile (File f){
        StringBuffer buf=new StringBuffer();
        try{
             BufferedReader reader=new BufferedReader(new FileReader(f));
             char[] c=new char[1];
             int res;
             while(true){
                res=reader.read(c);
                if (res<0) break;
                buf.append(c);
             }
             reader.close();
        }catch (Exception e){
             System.out.println(e.toString());
        }
        return(buf.toString());
    }
}
